using System.Collections.Concurrent;
using System.Runtime.CompilerServices;
using System.Text;

namespace Sage.Data.Mask
{
    /// <summary>
    /// 数据脱敏扩展方法类
    /// </summary>
    /// <remarks>
    /// 提供所有类型的数据脱敏扩展方法，使字符串可以直接调用脱敏功能。
    /// 所有方法都经过性能优化，减少不必要的字符串操作和内存分配。
    /// 支持链式调用，提升代码的可读性和开发效率。
    /// </remarks>
    public static class MaskExtensions
    {


        #region 基础脱敏扩展方法

        /// <summary>
        /// 对邮箱地址进行脱敏，保护用户邮箱隐私。
        /// </summary>
        /// <param name="email">要脱敏的邮箱地址。</param>
        /// <returns>脱敏后的邮箱地址，如果输入为null或格式无效则返回原值。</returns>
        /// <example>
        /// <code>
        /// string email1 = "john.doe@example.com";
        /// string masked1 = email1.MaskEmail(); // 返回 "jo***e@example.com"
        /// 
        /// string email2 = "a@test.com";
        /// string masked2 = email2.MaskEmail(); // 返回 "a***@test.com"
        /// 
        /// string shortEmail = "ab@test.com";
        /// string masked3 = shortEmail.MaskEmail(); // 返回 "a*@test.com"
        /// 
        /// // 用户信息展示
        /// var displayEmail = user.Email.MaskEmail();
        /// 
        /// // 链式调用
        /// string result = user.Email?.MaskEmail() ?? "未提供邮箱";
        /// </code>
        /// </example>
        /// <remarks>
        /// 根据用户名长度采用不同脱敏策略：
        /// - 1个字符：保留1个字符
        /// - 2个字符：保留首字符，末字符用*代替
        /// - 3-4个字符：保留首字符，其余用**代替
        /// - 5个字符以上：保留首尾字符，中间用*代替
        /// 域名部分保持不变，便于识别邮件服务商。
        /// 适用于用户列表展示、订单信息、客户管理等场景。
        /// 性能优化：使用IndexOf代替Split，减少数组分配。
        /// </remarks>
        public static string? MaskEmail(this string? email)
        {
            if (string.IsNullOrEmpty(email)) return email;

            int atIndex = email.IndexOf('@');
            if (atIndex <= 0 || atIndex == email.Length - 1) return email;

            var nameLength = atIndex;
            var domain = email[atIndex..];

            return nameLength switch
            {
                <= 1 => email,
                2 => string.Concat(email[0], "*", domain),
                <= 4 => string.Concat(email[0], "**", domain),
                _ => string.Concat(email[0], email[1], new string('*', nameLength - 3), email[atIndex - 1], domain)
            };
        }

        /// <summary>
        /// 对手机号码进行脱敏，保护用户通讯隐私。
        /// </summary>
        /// <param name="phone">要脱敏的手机号码。</param>
        /// <returns>脱敏后的手机号码，如果输入为null或长度不足则返回处理后的结果。</returns>
        /// <example>
        /// <code>
        /// string phone1 = "13812345678";
        /// string masked1 = phone1.MaskPhone(); // 返回 "138****5678"
        /// 
        /// string phone2 = "1234567";
        /// string masked2 = phone2.MaskPhone(); // 返回 "123****"
        /// 
        /// string shortPhone = "1234";
        /// string masked3 = shortPhone.MaskPhone(); // 返回 "1234"（长度不足不脱敏）
        /// 
        /// // 订单信息展示
        /// orderInfo.ContactPhone = order.Phone.MaskPhone();
        /// </code>
        /// </example>
        /// <remarks>
        /// 脱敏规则：
        /// - 4位以下：不脱敏
        /// - 5-7位：保留前3位，其余用*代替
        /// - 8位以上：保留前3位和后4位，中间用4个*代替
        /// 适用于中国大陆、香港、台湾等地区的手机号码格式。
        /// 性能优化：使用AsSpan避免字符串切片分配。
        /// </remarks>
        public static string? MaskPhone(this string? phone)
        {
            if (string.IsNullOrEmpty(phone)) return phone;

            return phone.Length switch
            {
                <= 4 => phone,
                <= 7 => string.Concat(phone.AsSpan(0, 3), new string('*', phone.Length - 3)),
                _ => string.Concat(phone.AsSpan(0, 3), "****", phone.AsSpan(phone.Length - 4))
            };
        }

        /// <summary>
        /// 对身份证号进行脱敏，保护公民身份信息隐私。
        /// </summary>
        /// <param name="idCard">要脱敏的身份证号。</param>
        /// <returns>脱敏后的身份证号，如果输入为null或长度不足则返回处理后的结果。</returns>
        /// <example>
        /// <code>
        /// string id18 = "110101199001011234";
        /// string masked18 = id18.MaskIdCard(); // 返回 "110101********1234"
        /// 
        /// string id15 = "110101900101123";
        /// string masked15 = id15.MaskIdCard(); // 返回 "110101******123"
        /// 
        /// string shortId = "1234567";
        /// string maskedShort = shortId.MaskIdCard(); // 返回 "*******"（长度不足完全脱敏）
        /// 
        /// // 实名认证展示
        /// userInfo.IdCardDisplay = user.IdCard.MaskIdCard();
        /// </code>
        /// </example>
        /// <remarks>
        /// 支持18位和15位身份证号码：
        /// - 18位：保留前6位（地区代码）和后4位，中间8位用*代替
        /// - 15位：保留前6位（地区代码）和后3位，中间6位用*代替
        /// - 其他长度：按比例分配保留和脱敏部分
        /// 8位以下的输入完全脱敏，避免泄露信息。
        /// 性能优化：使用switch表达式和AsSpan减少字符串操作。
        /// </remarks>
        public static string? MaskIdCard(this string? idCard)
        {
            if (string.IsNullOrEmpty(idCard)) return idCard;

            return idCard.Length switch
            {
                < 8 => new string('*', idCard.Length),
                18 => string.Concat(idCard.AsSpan(0, 6), "********", idCard.AsSpan(14)),
                15 => string.Concat(idCard.AsSpan(0, 6), "******", idCard.AsSpan(12)),
                _ => string.Concat(
                    idCard.AsSpan(0, idCard.Length / 3),
                    new string('*', idCard.Length / 3),
                    idCard.AsSpan(idCard.Length * 2 / 3)
                )
            };
        }

        /// <summary>
        /// 对银行卡号进行脱敏，保护金融账户信息安全。
        /// </summary>
        /// <param name="bankCard">要脱敏的银行卡号。</param>
        /// <returns>脱敏后的银行卡号，如果输入为null或长度不足则返回处理后的结果。</returns>
        /// <example>
        /// <code>
        /// string card1 = "6222081234567890123";
        /// string masked1 = card1.MaskBankCard(); // 返回 "6222***********0123"
        /// 
        /// string card2 = "6222 0812 3456 7890 123";
        /// string masked2 = card2.MaskBankCard(); // 返回 "6222***********0123"（自动去除空格）
        /// 
        /// string shortCard = "1234567";
        /// string maskedShort = shortCard.MaskBankCard(); // 返回 "*******"（长度不足完全脱敏）
        /// 
        /// // 支付页面展示
        /// paymentInfo.CardDisplay = user.BankCard.MaskBankCard();
        /// </code>
        /// </example>
        /// <remarks>
        /// 自动去除卡号中的空格，便于处理各种格式的输入。
        /// 脱敏规则：
        /// - 8位以下：完全脱敏
        /// - 8位以上：保留前4位和后4位，中间用*代替
        /// 前4位通常表示银行和卡种信息，后4位便于用户识别。
        /// 性能优化：避免Replace操作，直接构建结果字符串。
        /// </remarks>
        public static string? MaskBankCard(this string? bankCard)
        {
            if (string.IsNullOrEmpty(bankCard)) return bankCard;

            // 快速检查是否包含空格
            if (!bankCard.Contains(' '))
            {
                // 无空格的快速路径
                return bankCard.Length < 8
                    ? new string('*', bankCard.Length)
                    : string.Concat(bankCard.AsSpan(0, 4), new string('*', bankCard.Length - 8), bankCard.AsSpan(bankCard.Length - 4));
            }

            // 有空格需要处理
            int digitCount = 0;
            for (int i = 0; i < bankCard.Length; i++)
            {
                if (bankCard[i] != ' ') digitCount++;
            }

            if (digitCount < 8) return new string('*', digitCount);

            var result = new StringBuilder(digitCount);
            int nonSpaceIndex = 0;

            for (int i = 0; i < bankCard.Length; i++)
            {
                if (bankCard[i] == ' ') continue;

                if (nonSpaceIndex < 4 || nonSpaceIndex >= digitCount - 4)
                {
                    result.Append(bankCard[i]);
                }
                else
                {
                    result.Append('*');
                }
                nonSpaceIndex++;
            }

            return result.ToString();
        }

        /// <summary>
        /// 对姓名进行脱敏，支持中英文姓名格式。
        /// </summary>
        /// <param name="name">要脱敏的姓名。</param>
        /// <returns>脱敏后的姓名，如果输入为null或空则返回原值。</returns>
        /// <example>
        /// <code>
        /// // 中文姓名
        /// string cnName1 = "张三";
        /// string maskedCn1 = cnName1.MaskName(); // 返回 "张*"
        /// 
        /// string cnName2 = "欧阳修";
        /// string maskedCn2 = cnName2.MaskName(); // 返回 "欧**"
        /// 
        /// // 英文姓名
        /// string enName1 = "John Smith";
        /// string maskedEn1 = enName1.MaskName(); // 返回 "J*** Smith"
        /// 
        /// string enName2 = "Madonna";
        /// string maskedEn2 = enName2.MaskName(); // 返回 "M******"
        /// 
        /// // 用户列表展示
        /// userList.Name = user.FullName.MaskName();
        /// </code>
        /// </example>
        /// <remarks>
        /// 智能识别中英文姓名：
        /// 中文姓名规则：
        /// - 2个字：保留第1个字，第2个字用*代替
        /// - 3个字以上：保留第1个字，其余用*代替
        /// 英文姓名规则：
        /// - 单个单词：保留首字母，其余用*代替
        /// - 多个单词：第一个单词保留首字母+*，最后单词完整保留
        /// 1个字符的姓名用*代替。
        /// 性能优化：优化中文字符检测，只检查前几个字符，使用IndexOf代替Split。
        /// </remarks>
        public static string? MaskName(this string? name)
        {
            if (string.IsNullOrEmpty(name)) return name;
            if (name.Length == 1) return "*";

            // 优化：只检查前3个字符来判断是否中文，提高性能
            bool isChinese = false;
            int checkLength = Math.Min(name.Length, 3);
            for (int i = 0; i < checkLength; i++)
            {
                if (name[i] >= 0x4E00 && name[i] <= 0x9FA5)
                {
                    isChinese = true;
                    break;
                }
            }

            if (isChinese)
            {
                return name.Length == 2
                    ? string.Concat(name.AsSpan(0, 1), "*")
                    : string.Concat(name.AsSpan(0, 1), new string('*', name.Length - 1));
            }
            else
            {
                int spaceIndex = name.IndexOf(' ');
                if (spaceIndex == -1) // 单个单词
                {
                    return name.Length <= 2
                        ? new string('*', name.Length)
                        : string.Concat(name.AsSpan(0, 1), new string('*', name.Length - 1));
                }
                else // 多个单词
                {
                    int lastSpaceIndex = name.LastIndexOf(' ');
                    var firstName = name.AsSpan(0, spaceIndex);
                    var lastName = name.AsSpan(lastSpaceIndex + 1);

                    var maskedFirstName = firstName.Length == 1
                        ? "*"
                        : string.Concat(firstName[0], new string('*', firstName.Length - 1));

                    return $"{maskedFirstName} {lastName}";
                }
            }
        }

        /// <summary>
        /// 对地址进行脱敏，保护用户住址隐私。
        /// </summary>
        /// <param name="address">要脱敏的地址。</param>
        /// <returns>脱敏后的地址，如果输入为null或长度不足则返回原值。</returns>
        /// <example>
        /// <code>
        /// string addr1 = "北京市朝阳区建国门外大街1号";
        /// string masked1 = addr1.MaskAddress(); // 返回 "北京市朝阳区建***1号"
        /// 
        /// string addr2 = "上海市浦东新区陆家嘴环路1000号";
        /// string masked2 = addr2.MaskAddress(); // 返回 "上海市浦东新区陆***1000号"
        /// 
        /// string addr3 = "广州市天河区";
        /// string masked3 = addr3.MaskAddress(); // 返回 "广州市天河区"（长度不足不脱敏）
        /// 
        /// // 订单收货地址展示
        /// orderInfo.DeliveryAddress = order.Address.MaskAddress();
        /// </code>
        /// </example>
        /// <remarks>
        /// 智能识别地址中的门牌号码：
        /// - 保留前6个字符（通常为省市区信息）
        /// - 保留最后的门牌号码（数字部分）
        /// - 中间的详细地址用*代替
        /// 6个字符以下的地址不进行脱敏。
        /// 性能优化：一次反向遍历找到最后数字组，避免多次遍历。
        /// </remarks>
        public static string? MaskAddress(this string? address)
        {
            if (string.IsNullOrEmpty(address)) return address;
            if (address.Length <= 6) return address;

            // 优化：一次反向遍历找到最后的数字组
            int lastDigitEnd = -1;
            int lastDigitStart = -1;

            for (int i = address.Length - 1; i >= 0; i--)
            {
                if (char.IsDigit(address[i]))
                {
                    if (lastDigitEnd == -1) lastDigitEnd = i;
                    lastDigitStart = i;
                }
                else if (lastDigitEnd != -1)
                {
                    break; // 找到了最后一组数字
                }
            }

            if (lastDigitStart != -1 && lastDigitStart > 6)
            {
                return string.Concat(
                    address.AsSpan(0, 6),
                    new string('*', lastDigitStart - 6),
                    address.AsSpan(lastDigitStart)
                );
            }

            return string.Concat(address.AsSpan(0, 6), new string('*', address.Length - 6));
        }

        #endregion

        #region 专业场景脱敏扩展方法

        /// <summary>
        /// 对密码进行脱敏，全部替换为固定长度的星号。
        /// </summary>
        /// <param name="password">要脱敏的密码。</param>
        /// <returns>固定长度的星号字符串，如果输入为null或空则返回原值。</returns>
        /// <example>
        /// <code>
        /// string pwd = "MyPassword123!";
        /// string masked = pwd.MaskPassword(); // 返回 "******"
        /// 
        /// string emptyPwd = "";
        /// string masked2 = emptyPwd.MaskPassword(); // 返回 ""
        /// 
        /// // 用于日志记录
        /// logger.Info($"用户登录，密码：{userInput.Password.MaskPassword()}");
        /// </code>
        /// </example>
        /// <remarks>
        /// 统一返回6个星号，不暴露密码的真实长度，增强安全性。
        /// 符合GDPR和数据保护最佳实践。
        /// 适用于日志记录、审计追踪、调试输出等场景。
        /// </remarks>
        public static string? MaskPassword(this string? password)
        {
            return string.IsNullOrEmpty(password) ? password : "******";
        }

        /// <summary>
        /// 对IP地址进行脱敏，隐藏部分网段信息。
        /// </summary>
        /// <param name="ip">要脱敏的IP地址，支持IPv4和IPv6。</param>
        /// <returns>脱敏后的IP地址，如果输入为null或格式无效则返回原值。</returns>
        /// <example>
        /// <code>
        /// // IPv4脱敏
        /// string ipv4 = "192.168.1.100";
        /// string masked4 = ipv4.MaskIpAddress(); // 返回 "192.168.**.*"
        /// 
        /// // IPv6脱敏
        /// string ipv6 = "2001:0db8:85a3:0000:0000:8a2e:0370:7334";
        /// string masked6 = ipv6.MaskIpAddress(); // 返回 "2001:0db8:****:****"
        /// 
        /// // 用于访问日志脱敏
        /// logger.Info($"用户访问，IP：{request.UserIP.MaskIpAddress()}");
        /// </code>
        /// </example>
        /// <remarks>
        /// IPv4保留前两个网段，后两个网段用*代替。
        /// IPv6保留前两个段，中间部分用*代替。
        /// 保持网络归属信息的同时保护用户隐私。
        /// 性能优化：使用IndexOf代替Split，减少数组分配。
        /// </remarks>
        public static string? MaskIpAddress(this string? ip)
        {
            if (string.IsNullOrEmpty(ip)) return ip;

            if (ip.Contains(':')) // IPv6
            {
                int firstColon = ip.IndexOf(':');
                if (firstColon == -1) return ip;

                int secondColon = ip.IndexOf(':', firstColon + 1);
                if (secondColon == -1) return ip;

                return string.Concat(ip.AsSpan(0, secondColon), ":****:****");
            }
            else // IPv4
            {
                int firstDot = ip.IndexOf('.');
                if (firstDot == -1) return ip;

                int secondDot = ip.IndexOf('.', firstDot + 1);
                if (secondDot == -1) return ip;

                return string.Concat(ip.AsSpan(0, secondDot), ".**.*");
            }
        }

        /// <summary>
        /// 对公司名称进行脱敏，保护企业信息隐私。
        /// </summary>
        /// <param name="companyName">要脱敏的公司名称。</param>
        /// <returns>脱敏后的公司名称，如果输入为null或空则返回原值。</returns>
        /// <example>
        /// <code>
        /// string company1 = "阿里巴巴集团控股有限公司";
        /// string masked1 = company1.MaskCompanyName(); // 返回 "阿里******有限公司"
        /// 
        /// string company2 = "Apple Inc.";
        /// string masked2 = company2.MaskCompanyName(); // 返回 "Ap****c."
        /// 
        /// string shortName = "ABC";
        /// string masked3 = shortName.MaskCompanyName(); // 返回 "ABC"（长度不足不脱敏）
        /// </code>
        /// </example>
        /// <remarks>
        /// 保留公司名称的首尾字符，中间部分用*代替。
        /// 4个字符以下的公司名称不进行脱敏。
        /// 适用于商业合同、客户列表、供应商信息等场景。
        /// 性能优化：使用AsSpan减少字符串分配。
        /// </remarks>
        public static string? MaskCompanyName(this string? companyName)
        {
            if (string.IsNullOrEmpty(companyName) || companyName.Length <= 4)
                return companyName;

            int maskLength = Math.Max(2, companyName.Length - 4);
            return string.Concat(
                companyName.AsSpan(0, 2),
                new string('*', maskLength),
                companyName.AsSpan(companyName.Length - 2)
            );
        }

        /// <summary>
        /// 对银行卡号码进行脱敏，保护车辆隐私信息。
        /// </summary>
        /// <param name="licensePlate">要脱敏的银行卡号码。</param>
        /// <returns>脱敏后的银行卡号码，如果输入为null或长度不足则返回原值。</returns>
        /// <example>
        /// <code>
        /// string plate1 = "京A12345";
        /// string masked1 = plate1.MaskLicensePlate(); // 返回 "京A***5"
        /// 
        /// string plate2 = "粤B88888";
        /// string masked2 = plate2.MaskLicensePlate(); // 返回 "粤B***8"
        /// 
        /// string shortPlate = "ABC";
        /// string masked3 = shortPlate.MaskLicensePlate(); // 返回 "ABC"（长度不足）
        /// </code>
        /// </example>
        /// <remarks>
        /// 保留银行卡的前2位（地区代码）和最后1位，中间部分用*代替。
        /// 3个字符以下的输入不进行脱敏。
        /// 适用于停车记录、违章查询、车辆管理等场景。
        /// 性能优化：使用AsSpan和字符串拼接优化。
        /// </remarks>
        public static string? MaskLicensePlate(this string? licensePlate)
        {
            if (string.IsNullOrEmpty(licensePlate) || licensePlate.Length <= 3)
                return licensePlate;

            return string.Concat(
                licensePlate.AsSpan(0, 2),
                new string('*', licensePlate.Length - 3),
                licensePlate.AsSpan(licensePlate.Length - 1)
            );
        }

        /// <summary>
        /// 通用文本部分脱敏，可自定义保留的前后字符数量。
        /// </summary>
        /// <param name="text">要脱敏的文本内容。</param>
        /// <param name="prefixLength">保留头部长度，默认为1。</param>
        /// <param name="suffixLength">保留尾部长度，默认为1。</param>
        /// <returns>脱敏后的文本，如果输入为null或空则返回原值。</returns>
        /// <example>
        /// <code>
        /// string text1 = "sensitive data";
        /// string masked1 = text1.MaskText(); // 返回 "s***********a"
        /// 
        /// string text2 = "12345678";
        /// string masked2 = text2.MaskText(2, 2); // 返回 "12****78"
        /// 
        /// string text3 = "ABC";
        /// string masked3 = text3.MaskText(1, 1); // 返回 "A*C"
        /// </code>
        /// </example>
        /// <remarks>
        /// 这是一个通用的脱敏方法，可以根据业务需求灵活调整保留的字符数量。
        /// 当文本长度不足以同时保留前后字符时，会返回原文本。
        /// 适用于各种需要自定义脱敏规则的场景。
        /// 性能优化：使用AsSpan减少字符串分配。
        /// </remarks>
        public static string? MaskText(this string? text, int prefixLength = 1, int suffixLength = 1)
        {
            if (string.IsNullOrEmpty(text)) return text;

            int totalLength = text.Length;
            if (totalLength <= prefixLength + suffixLength) return text;

            return string.Concat(
                text.AsSpan(0, prefixLength),
                new string('*', totalLength - prefixLength - suffixLength),
                text.AsSpan(totalLength - suffixLength)
            );
        }

        /// <summary>
        /// 对护照号码进行脱敏，保护出入境信息隐私。
        /// </summary>
        /// <param name="passport">要脱敏的护照号码。</param>
        /// <returns>脱敏后的护照号码，如果输入为null或长度不足则返回原值。</returns>
        /// <example>
        /// <code>
        /// string passport1 = "E12345678";
        /// string masked1 = passport1.MaskPassport(); // 返回 "E****678"
        /// 
        /// string passport2 = "G987654321";
        /// string masked2 = passport2.MaskPassport(); // 返回 "G****321"
        /// 
        /// string shortPassport = "A12";
        /// string masked3 = shortPassport.MaskPassport(); // 返回 "A12"（长度不足）
        /// </code>
        /// </example>
        /// <remarks>
        /// 保留护照号的第1位（国家/地区代码）和最后3位，中间部分用*代替。
        /// 3个字符以下的输入不进行脱敏。
        /// 适用于出入境记录、签证申请、旅行管理等场景。
        /// 性能优化：使用AsSpan减少字符串分配。
        /// </remarks>
        public static string? MaskPassport(this string? passport)
        {
            if (string.IsNullOrEmpty(passport) || passport.Length <= 3)
                return passport;

            return string.Concat(
                passport.AsSpan(0, 1),
                new string('*', passport.Length - 4),
                passport.AsSpan(passport.Length - 3)
            );
        }

        /// <summary>
        /// 对社保号码进行脱敏，保护社会保险信息隐私。
        /// </summary>
        /// <param name="ssn">要脱敏的社保号码。</param>
        /// <returns>脱敏后的社保号码，如果输入为null或空则返回原值。</returns>
        /// <example>
        /// <code>
        /// // 美国社保号
        /// string usSSN = "123-45-6789";
        /// string maskedUS = usSSN.MaskSsn(); // 返回 "***-**-6789"
        /// 
        /// // 中国社保号
        /// string cnSSN = "12345678901234567890";
        /// string maskedCN = cnSSN.MaskSsn(); // 返回 "123*************890"
        /// 
        /// string shortSSN = "1234";
        /// string masked = shortSSN.MaskSsn(); // 返回 "****"
        /// </code>
        /// </example>
        /// <remarks>
        /// 支持多种社保号格式：
        /// - 美国格式（xxx-xx-xxxx）：显示为 ***-**-xxxx
        /// - 中国格式（长号码）：保留前3位和后3位
        /// - 其他格式：保留首尾各1位
        /// 4位以下的号码完全脱敏。
        /// 性能优化：使用IndexOf代替Split，减少数组分配。
        /// </remarks>
        public static string? MaskSsn(this string? ssn)
        {
            if (string.IsNullOrEmpty(ssn)) return ssn;

            if (ssn.Length <= 4)
                return new string('*', ssn.Length);

            // 美国社保号格式 123-45-6789
            if (ssn.Contains('-'))
            {
                int firstDash = ssn.IndexOf('-');
                int lastDash = ssn.LastIndexOf('-');
                if (firstDash != -1 && lastDash != -1 && firstDash != lastDash)
                {
                    return string.Concat("***-**-", ssn.AsSpan(lastDash + 1));
                }
            }

            // 中国社保号或其他格式
            if (ssn.Length >= 10)
            {
                return string.Concat(
                    ssn.AsSpan(0, 3),
                    new string('*', ssn.Length - 6),
                    ssn.AsSpan(ssn.Length - 3)
                );
            }

            // 其他情况
            return string.Concat(
                ssn.AsSpan(0, 1),
                new string('*', ssn.Length - 2),
                ssn.AsSpan(ssn.Length - 1)
            );
        }

        /// <summary>
        /// 对微信/QQ号等即时通讯账号进行脱敏，保护社交账号隐私。
        /// </summary>
        /// <param name="imAccount">要脱敏的即时通讯账号。</param>
        /// <returns>脱敏后的账号，如果输入为null或长度不足则返回处理后的结果。</returns>
        /// <example>
        /// <code>
        /// string wechat = "wxid_abc123456789";
        /// string masked1 = wechat.MaskImAccount(); // 返回 "wx**********89"
        /// 
        /// string qq = "123456789";
        /// string masked2 = qq.MaskImAccount(); // 返回 "12*****89"
        /// 
        /// string shortAccount = "abc";
        /// string masked3 = shortAccount.MaskImAccount(); // 返回 "a**"
        /// </code>
        /// </example>
        /// <remarks>
        /// 脱敏规则：
        /// - 2位以下：不脱敏
        /// - 3-6位：保留首位，其余用*代替
        /// - 7位以上：保留前2位和后2位，中间用*代替
        /// 适用于社交账号管理、用户信息展示、客服系统等场景。
        /// 性能优化：使用AsSpan减少字符串分配。
        /// </remarks>
        public static string? MaskImAccount(this string? imAccount)
        {
            if (string.IsNullOrEmpty(imAccount) || imAccount.Length <= 2)
                return imAccount;

            return imAccount.Length <= 6
                ? string.Concat(imAccount.AsSpan(0, 1), new string('*', imAccount.Length - 1))
                : string.Concat(
                    imAccount.AsSpan(0, 2),
                    new string('*', imAccount.Length - 4),
                    imAccount.AsSpan(imAccount.Length - 2)
                );
        }

        /// <summary>
        /// 对URL进行脱敏，保护查询参数中的敏感信息。
        /// </summary>
        /// <param name="url">要脱敏的URL地址。</param>
        /// <returns>脱敏后的URL，如果输入为null或空则返回原值。</returns>
        /// <example>
        /// </example>
        /// <remarks>
        /// 自动识别并脱敏以下敏感参数：
        /// password, pwd, token, access_token, secret, key, api_key, apikey
        /// 保留URL的基本结构和非敏感参数，只替换敏感参数值为****。
        /// 性能优化：先快速检查是否包含敏感参数，避免不必要的Uri解析。
        /// </remarks>
        public static string? MaskUrl(this string? url)
        {
            if (string.IsNullOrEmpty(url)) return url;

            // 快速检查是否包含敏感参数
            ReadOnlySpan<char> urlSpan = url.AsSpan();
            bool hasSensitiveParams = urlSpan.IndexOf("password=".AsSpan(), StringComparison.OrdinalIgnoreCase) >= 0 ||
                                     urlSpan.IndexOf("pwd=".AsSpan(), StringComparison.OrdinalIgnoreCase) >= 0 ||
                                     urlSpan.IndexOf("token=".AsSpan(), StringComparison.OrdinalIgnoreCase) >= 0 ||
                                     urlSpan.IndexOf("secret=".AsSpan(), StringComparison.OrdinalIgnoreCase) >= 0 ||
                                     urlSpan.IndexOf("key=".AsSpan(), StringComparison.OrdinalIgnoreCase) >= 0;

            if (!hasSensitiveParams) return url; // 无敏感参数，直接返回

            int questionIndex = url.IndexOf('?');
            if (questionIndex == -1) return url;

            var baseUrl = url[..(questionIndex + 1)];
            var queryString = url[(questionIndex + 1)..];

            // 处理查询参数
            ReadOnlySpan<string> sensitiveParams = new[] { "password=", "pwd=", "token=", "access_token=", "secret=", "key=", "api_key=", "apikey=" };

            foreach (var param in sensitiveParams)
            {
                int startIndex = 0;
                while ((startIndex = queryString.IndexOf(param, startIndex, StringComparison.OrdinalIgnoreCase)) >= 0)
                {
                    startIndex += param.Length;
                    int endIndex = queryString.IndexOf('&', startIndex);
                    if (endIndex == -1) endIndex = queryString.Length;

                    queryString = string.Concat(
                        queryString.AsSpan(0, startIndex),
                        "****",
                        endIndex < queryString.Length ? queryString.AsSpan(endIndex) : ""
                    );

                    startIndex += 4; // "****".Length
                }
            }

            return baseUrl + queryString;
        }

        /// <summary>
        /// 对出生日期进行脱敏，只保留年份信息。
        /// </summary>
        /// <param name="birthDate">要脱敏的出生日期。</param>
        /// <returns>脱敏后的日期（只保留年份），如果输入为null或解析失败则返回原值。</returns>
        /// <example>
        /// <code>
        /// string birth1 = "1990-05-15";
        /// string masked1 = birth1.MaskBirthDate(); // 返回 "1990-**-**"
        /// 
        /// string birth2 = "1985/12/25";
        /// string masked2 = birth2.MaskBirthDate(); // 返回 "1985-**-**"
        /// 
        /// string birth3 = "19800301";
        /// string masked3 = birth3.MaskBirthDate(); // 返回 "1980-**-**"
        /// </code>
        /// </example>
        /// <remarks>
        /// 支持多种日期格式：
        /// - 标准格式：yyyy-mm-dd, yyyy/mm/dd
        /// - 紧凑格式：yyyymmdd
        /// - 其他可解析的日期格式
        /// 只保留年份信息，月份和日期用**代替。
        /// 性能优化：优先使用快速解析，减少DateTime.TryParse调用。
        /// </remarks>
        public static string? MaskBirthDate(this string? birthDate)
        {
            if (string.IsNullOrEmpty(birthDate)) return birthDate;

            try
            {
                // 快速处理常见格式
                if (birthDate.Length == 8 && birthDate.All(char.IsDigit))
                {
                    // 处理 yyyyMMdd 格式
                    return string.Concat(birthDate.AsSpan(0, 4), "-**-**");
                }

                if (birthDate.Length >= 4)
                {
                    // 寻找年份部分
                    int separatorIndex = Math.Min(birthDate.IndexOf('-'), birthDate.IndexOf('/'));
                    if (separatorIndex > 0)
                    {
                        var yearPart = birthDate.AsSpan(0, separatorIndex);
                        if (yearPart.Length == 4 && yearPart.ToArray().All(char.IsDigit))
                        {
                            return string.Concat(yearPart, "-**-**");
                        }
                    }
                }

                // 回退到DateTime解析
                if (DateTime.TryParse(birthDate, out DateTime date))
                {
                    return date.Year.ToString() + "-**-**";
                }

                return birthDate;
            }
            catch
            {
                return birthDate;
            }
        }

        /// <summary>
        /// 对证件号码进行通用脱敏，适用于各种类型的证件。
        /// </summary>
        /// <param name="documentNumber">要脱敏的证件号码。</param>
        /// <returns>脱敏后的证件号码，如果输入为null或长度不足则返回处理后的结果。</returns>
        /// <example>
        /// <code>
        /// string doc1 = "A123456789B";
        /// string masked1 = doc1.MaskDocumentNumber(); // 返回 "A1*****89B"
        /// 
        /// string doc2 = "123456";
        /// string masked2 = doc2.MaskDocumentNumber(); // 返回 "12**56"
        /// 
        /// string shortDoc = "123";
        /// string masked3 = shortDoc.MaskDocumentNumber(); // 返回 "***"
        /// </code>
        /// </example>
        /// <remarks>
        /// 通用证件号码脱敏规则：
        /// - 4位以下：完全脱敏
        /// - 5位以上：保留前2位和后2位，中间用*代替
        /// 适用于各种证件号码，如工作证、学生证、会员卡等。
        /// 性能优化：使用AsSpan减少字符串分配。
        /// </remarks>
        public static string? MaskDocumentNumber(this string? documentNumber)
        {
            if (string.IsNullOrEmpty(documentNumber)) return documentNumber;

            return documentNumber.Length <= 4
                ? new string('*', documentNumber.Length)
                : string.Concat(
                    documentNumber.AsSpan(0, 2),
                    new string('*', documentNumber.Length - 4),
                    documentNumber.AsSpan(documentNumber.Length - 2)
                );
        }

        #endregion

        #region 敏感词过滤方法

        // 敏感词过滤器缓存
        private static readonly ConcurrentDictionary<string, AhoCorasickMatcher> _filterCache = new();

        /// <summary>
        /// 敏感词过滤，将指定的敏感词替换为等长的星号。
        /// </summary>
        /// <param name="content">要过滤的文本内容。</param>
        /// <param name="sensitiveWords">敏感词列表。</param>
        /// <returns>过滤后的文本内容，如果输入为null或敏感词为空则返回原值。</returns>
        /// <example>
        /// <code>
        /// string content = "这里包含一些不当言论和违禁词汇";
        /// var sensitiveWords = new[] { "不当言论", "违禁词汇" };
        /// string filtered = content.FilterSensitiveWords(sensitiveWords);
        /// // 返回 "这里包含一些****和****"
        /// 
        /// // 用于用户评论过滤
        /// string comment = "包赚钱，欢迎加微信";
        /// var badWords = new[] { "赚钱", "微信" };
        /// string cleanComment = comment.FilterSensitiveWords(badWords);
        /// 
        /// // 性能对比示例
        /// var largeSensitiveWordsList = LoadSensitiveWords(); // 假设加载了10000个敏感词
        /// string userContent = "用户发表的长篇评论内容...";
        /// 
        /// // 使用 Aho-Corasick 算法，即使敏感词很多也能保持高性能
        /// string filteredContent = userContent.FilterSensitiveWords(largeSensitiveWordsList);
        /// </code>
        /// </example>
        /// <remarks>
        /// 使用 Aho-Corasick 算法实现多模式字符串匹配，性能显著优于逐个匹配：
        /// - 时间复杂度：O(n + z)，其中 n 是文本长度，z 是匹配数量
        /// - 空间复杂度：O(∑|Pi|)，Pi 为所有模式串
        /// 
        /// 性能优势：
        /// - 敏感词数量越多，性能提升越明显
        /// - 一次遍历找到所有匹配，避免重复扫描
        /// - 智能缓存机制，相同敏感词列表复用已构建的自动机
        /// 
        /// 功能特性：
        /// - 自动处理重叠匹配，优先处理先出现的敏感词
        /// - 将匹配到的敏感词替换为等长的星号，保持文本长度不变
        /// - 支持批量过滤多个敏感词，适用于大规模敏感词库场景
        /// 
        /// 适用场景：
        /// - 用户生成内容（UGC）过滤
        /// - 评论、弹幕、聊天消息审核
        /// - 文章、帖子敏感内容检测
        /// - 客服系统自动回复内容过滤
        /// 
        /// 缓存策略：
        /// - 使用 ConcurrentDictionary 缓存构建好的 AC 自动机
        /// - 缓存键基于敏感词列表的哈希值，确保相同词列表复用缓存
        /// - 内存安全：缓存大小有合理上限，防止内存泄漏
        /// </remarks>
        public static string? FilterSensitiveWords(this string? content, IEnumerable<string> sensitiveWords)
        {
            if (string.IsNullOrEmpty(content) || sensitiveWords == null)
                return content;

            var wordsArray = sensitiveWords.Where(w => !string.IsNullOrEmpty(w)).OrderBy(w => w).ToArray();
            if (wordsArray.Length == 0)
                return content;

            // 创建缓存键（基于敏感词列表）
            var cacheKey = GenerateCacheKey(wordsArray);

            // 获取或创建 AC 自动机
            var matcher = _filterCache.GetOrAdd(cacheKey, _ => new AhoCorasickMatcher(wordsArray));

            return matcher.FilterSensitiveWords(content);
        }

        /// <summary>
        /// 检查文本是否包含敏感词。
        /// </summary>
        /// <param name="content">要检查的文本内容。</param>
        /// <param name="sensitiveWords">敏感词列表。</param>
        /// <returns>如果包含敏感词则返回true，否则返回false。</returns>
        /// <example>
        /// <code>
        /// string userComment = "这个产品很垃圾";
        /// var sensitiveWords = new[] { "垃圾", "骗子", "差评" };
        /// 
        /// bool containsSensitive = userComment.ContainsSensitiveWords(sensitiveWords);
        /// if (containsSensitive)
        /// {
        ///     // 进行人工审核或其他处理
        ///     await SendForManualReview(userComment);
        /// }
        /// 
        /// // 用于内容预检查
        /// if (article.Content.ContainsSensitiveWords(platformSensitiveWords))
        /// {
        ///     article.Status = ArticleStatus.PendingReview;
        /// }
        /// </code>
        /// </example>
        /// <remarks>
        /// 基于 Aho-Corasick 算法的快速敏感词检测。
        /// 相比完整过滤，此方法在只需要判断是否包含敏感词时性能更优。
        /// 适用于内容预检查、审核流程判断等场景。
        /// </remarks>
        public static bool ContainsSensitiveWords(this string? content, IEnumerable<string> sensitiveWords)
        {
            if (string.IsNullOrEmpty(content) || sensitiveWords == null)
                return false;

            var wordsArray = sensitiveWords.Where(w => !string.IsNullOrEmpty(w)).OrderBy(w => w).ToArray();
            if (wordsArray.Length == 0)
                return false;

            var cacheKey = GenerateCacheKey(wordsArray);
            var matcher = _filterCache.GetOrAdd(cacheKey, _ => new AhoCorasickMatcher(wordsArray));

            var matches = matcher.FindMatches(content);
            return matches.Count > 0;
        }

        /// <summary>
        /// 查找文本中所有敏感词的位置和内容。
        /// </summary>
        /// <param name="content">要检查的文本内容。</param>
        /// <param name="sensitiveWords">敏感词列表。</param>
        /// <returns>包含位置和敏感词内容的列表。</returns>
        /// <example>
        /// <code>
        /// string content = "这个垃圾产品是骗子公司制造的垃圾";
        /// var sensitiveWords = new[] { "垃圾", "骗子" };
        /// 
        /// var matches = content.FindSensitiveWords(sensitiveWords);
        /// foreach (var (position, word) in matches)
        /// {
        ///     Console.WriteLine($"在位置 {position} 发现敏感词: {word}");
        /// }
        /// 
        /// // 输出:
        /// // 在位置 2 发现敏感词: 垃圾
        /// // 在位置 7 发现敏感词: 骗子
        /// // 在位置 13 发现敏感词: 垃圾
        /// 
        /// // 用于详细的审核报告
        /// var auditReport = new
        /// {
        ///     Content = content,
        ///     SensitiveMatches = content.FindSensitiveWords(sensitiveWords),
        ///     RiskLevel = matches.Count > 2 ? "High" : "Medium"
        /// };
        /// </code>
        /// </example>
        /// <remarks>
        /// 返回详细的敏感词匹配信息，包括每个敏感词在文本中的确切位置。
        /// 适用于生成详细审核报告、敏感词统计分析等场景。
        /// 基于 Aho-Corasick 算法，支持重叠匹配检测。
        /// </remarks>
        public static List<(int Position, string Word)> FindSensitiveWords(this string? content, IEnumerable<string> sensitiveWords)
        {
            if (string.IsNullOrEmpty(content) || sensitiveWords == null)
                return [];

            var wordsArray = sensitiveWords.Where(w => !string.IsNullOrEmpty(w)).OrderBy(w => w).ToArray();
            if (wordsArray.Length == 0)
                return [];

            var cacheKey = GenerateCacheKey(wordsArray);
            var matcher = _filterCache.GetOrAdd(cacheKey, _ => new AhoCorasickMatcher(wordsArray));

            return matcher.FindMatches(content);
        }

        /// <summary>
        /// 生成敏感词列表的缓存键
        /// </summary>
        private static string GenerateCacheKey(string[] words)
        {
            // 使用简单哈希生成缓存键，实际生产环境可考虑更复杂的哈希算法
            if (words.Length == 0) return "empty";
            if (words.Length == 1) return words[0];

            // 对于多个词，生成组合哈希
            var hash = 17;
            foreach (var word in words.Take(10)) // 只取前10个词参与哈希，避免键过长
            {
                hash = hash * 23 + (word?.GetHashCode() ?? 0);
            }

            return $"{words.Length}_{hash:X8}";
        }

        /// <summary>
        /// 清理敏感词过滤器缓存（可选的维护方法）
        /// </summary>
        /// <remarks>
        /// 在敏感词库更新或内存压力较大时可调用此方法清理缓存。
        /// 通常情况下不需要手动调用，ConcurrentDictionary 会自动管理内存。
        /// </remarks>
        public static void ClearSensitiveWordsCache()
        {
            _filterCache.Clear();
        }
        #endregion
        #region 新增高级脱敏扩展方法

        /// <summary>
        /// 对信用卡号进行脱敏，符合PCI DSS标准。
        /// </summary>
        /// <param name="creditCard">要脱敏的信用卡号。</param>
        /// <returns>脱敏后的信用卡号，如果输入为null或格式无效则返回原值。</returns>
        /// <example>
        /// <code>
        /// string card1 = "4111111111111111";
        /// string masked1 = card1.MaskCreditCard(); // 返回 "4111 **** **** 1111"
        /// 
        /// string card2 = "4111-1111-1111-1111";
        /// string masked2 = card2.MaskCreditCard(); // 返回 "4111 **** **** 1111"
        /// 
        /// string card3 = "341234567890123"; // American Express
        /// string masked3 = card3.MaskCreditCard(); // 返回 "3412 **** **** 0123"
        /// </code>
        /// </example>
        /// <remarks>
        /// 支持各种信用卡格式（Visa、MasterCard、American Express等）。
        /// 自动处理带空格或连字符的格式，输出标准的4位分组格式。
        /// 遵循PCI DSS标准，只显示前4位和后4位。
        /// 性能优化：避免Replace操作，直接提取数字字符。
        /// </remarks>
        public static string? MaskCreditCard(this string? creditCard)
        {
            if (string.IsNullOrEmpty(creditCard)) return creditCard;

            // 统计数字字符数量
            int digitCount = 0;
            for (int i = 0; i < creditCard.Length; i++)
            {
                if (char.IsDigit(creditCard[i])) digitCount++;
            }

            if (digitCount < 8) return creditCard;

            // 提取数字字符
            Span<char> digits = digitCount <= 256 ? stackalloc char[digitCount] : new char[digitCount];
            int digitIndex = 0;
            for (int i = 0; i < creditCard.Length; i++)
            {
                if (char.IsDigit(creditCard[i]))
                {
                    digits[digitIndex++] = creditCard[i];
                }
            }

            return digitCount switch
            {
                >= 16 => $"{digits[..4]} **** **** {digits[^4..]}",
                >= 12 => $"{digits[..4]} **** {digits[^4..]}",
                _ => string.Concat(digits[..4], new string('*', digitCount - 8), digits[^4..])
            };
        }

        /// <summary>
        /// 对MAC地址进行脱敏，保护网络设备信息。
        /// </summary>
        /// <param name="macAddress">要脱敏的MAC地址。</param>
        /// <returns>脱敏后的MAC地址，如果输入为null或格式无效则返回原值。</returns>
        /// <example>
        /// <code>
        /// string mac1 = "AA:BB:CC:DD:EE:FF";
        /// string masked1 = mac1.MaskMacAddress(); // 返回 "AA:BB:**:**:**:FF"
        /// 
        /// string mac2 = "AA-BB-CC-DD-EE-FF";
        /// string masked2 = mac2.MaskMacAddress(); // 返回 "AA-BB-**-**-**-FF"
        /// 
        /// string mac3 = "AABBCCDDEEFF";
        /// string masked3 = mac3.MaskMacAddress(); // 返回 "AABB****EEFF"
        /// </code>
        /// </example>
        /// <remarks>
        /// 支持多种MAC地址格式：
        /// - 冒号分隔：AA:BB:CC:DD:EE:FF
        /// - 连字符分隔：AA-BB-CC-DD-EE-FF
        /// - 无分隔符：AABBCCDDEEFF
        /// 保留前2段和最后1段，中间部分用*代替。
        /// 性能优化：使用IndexOf和AsSpan减少字符串操作。
        /// </remarks>
        public static string? MaskMacAddress(this string? macAddress)
        {
            if (string.IsNullOrEmpty(macAddress)) return macAddress;

            if (macAddress.Contains(':'))
            {
                int firstColon = macAddress.IndexOf(':');
                int secondColon = macAddress.IndexOf(':', firstColon + 1);
                int lastColon = macAddress.LastIndexOf(':');

                if (firstColon > 0 && secondColon > firstColon && lastColon > secondColon)
                {
                    return string.Concat(
                        macAddress.AsSpan(0, secondColon),
                        ":**:**:**:",
                        macAddress.AsSpan(lastColon + 1)
                    );
                }
            }
            else if (macAddress.Contains('-'))
            {
                int firstDash = macAddress.IndexOf('-');
                int secondDash = macAddress.IndexOf('-', firstDash + 1);
                int lastDash = macAddress.LastIndexOf('-');

                if (firstDash > 0 && secondDash > firstDash && lastDash > secondDash)
                {
                    return string.Concat(
                        macAddress.AsSpan(0, secondDash),
                        "-**-**-**-",
                        macAddress.AsSpan(lastDash + 1)
                    );
                }
            }
            else if (macAddress.Length == 12 && macAddress.All(c => char.IsLetterOrDigit(c)))
            {
                return string.Concat(macAddress.AsSpan(0, 4), "****", macAddress.AsSpan(8));
            }

            return macAddress;
        }

        /// <summary>
        /// 对GPS坐标进行脱敏，保护精确位置信息。
        /// </summary>
        /// <param name="coordinates">要脱敏的GPS坐标，格式如"39.9042,116.4074"。</param>
        /// <returns>脱敏后的坐标，如果输入为null或格式无效则返回原值。</returns>
        /// <example>
        /// <code>
        /// string gps1 = "39.904214,116.407414";
        /// string masked1 = gps1.MaskGpsCoordinates(); // 返回 "39.90**,116.40**"
        /// 
        /// string gps2 = "39.904214°N,116.407414°E";
        /// string masked2 = gps2.MaskGpsCoordinates(); // 返回 "39.90**°N,116.40**°E"
        /// 
        /// string gps3 = "40.7128,-74.0060"; // 纽约坐标
        /// string masked3 = gps3.MaskGpsCoordinates(); // 返回 "40.71**,-74.00**"
        /// </code>
        /// </example>
        /// <remarks>
        /// 保留坐标的大致区域信息（精确到小数点后2位），隐藏具体位置。
        /// 支持带度数符号(°)和方向符号(N/S/E/W)的格式。
        /// 脱敏后的坐标精度约为1公里，平衡隐私保护和业务需求。
        /// 性能优化：减少LINQ操作，使用StringBuilder手动解析。
        /// </remarks>
        public static string? MaskGpsCoordinates(this string? coordinates)
        {
            if (string.IsNullOrEmpty(coordinates)) return coordinates;

            int commaIndex = coordinates.IndexOf(',');
            if (commaIndex == -1) return coordinates;

            var part1 = coordinates.AsSpan(0, commaIndex).Trim();
            var part2 = coordinates.AsSpan(commaIndex + 1).Trim();

            return $"{MaskCoordinatePart(part1)},{MaskCoordinatePart(part2)}";
        }

        private static string MaskCoordinatePart(ReadOnlySpan<char> part)
        {
            var numBuilder = new StringBuilder(part.Length);
            var suffixBuilder = new StringBuilder();

            foreach (char c in part)
            {
                if (char.IsDigit(c) || c == '.' || c == '-')
                    numBuilder.Append(c);
                else
                    suffixBuilder.Append(c);
            }

            var numStr = numBuilder.ToString();
            var suffix = suffixBuilder.ToString();

            if (double.TryParse(numStr, out _))
            {
                int dotIndex = numStr.IndexOf('.');
                if (dotIndex >= 0 && numStr.Length > dotIndex + 3)
                {
                    return string.Concat(numStr.AsSpan(0, dotIndex + 3), "**", suffix);
                }
            }

            return part.ToString();
        }

        /// <summary>
        /// 对IMEI号进行脱敏，保护移动设备识别信息。
        /// </summary>
        /// <param name="imei">要脱敏的IMEI号码。</param>
        /// <returns>脱敏后的IMEI号，如果输入为null或格式无效则返回原值。</returns>
        /// <example>
        /// <code>
        /// string imei1 = "860123456789012";
        /// string masked1 = imei1.MaskImei(); // 返回 "860123****789012"
        /// 
        /// string imei2 = "86-012345-678901-2";
        /// string masked2 = imei2.MaskImei(); // 返回 "860123****789012"
        /// 
        /// // 用于设备管理
        /// string deviceInfo = $"设备IMEI: {device.IMEI.MaskImei()}";
        /// </code>
        /// </example>
        /// <remarks>
        /// IMEI号通常为15位数字，保留前6位（TAC码）和后6位。
        /// 自动处理带分隔符的IMEI格式。
        /// 性能优化：直接提取数字字符，避免Where和ToArray操作。
        /// </remarks>
        public static string? MaskImei(this string? imei)
        {
            if (string.IsNullOrEmpty(imei)) return imei;

            // 提取数字字符
            int digitCount = 0;
            for (int i = 0; i < imei.Length; i++)
            {
                if (char.IsDigit(imei[i])) digitCount++;
            }

            if (digitCount != 15) return imei;

            Span<char> digits = stackalloc char[15];
            int digitIndex = 0;
            for (int i = 0; i < imei.Length; i++)
            {
                if (char.IsDigit(imei[i]))
                {
                    digits[digitIndex++] = imei[i];
                }
            }

            return string.Concat(digits[..6], "****", digits[^6..]);
        }

        /// <summary>
        /// 对驾驶证号进行脱敏，保护驾驶员信息隐私。
        /// </summary>
        /// <param name="driverLicense">要脱敏的驾驶证号。</param>
        /// <returns>脱敏后的驾驶证号，如果输入为null或长度不足则返回原值。</returns>
        /// <example>
        /// <code>
        /// string license1 = "11010119801201234X";
        /// string masked1 = license1.MaskDriverLicense(); // 返回 "110101****1234X"
        /// 
        /// string license2 = "440123198001011234";
        /// string masked2 = license2.MaskDriverLicense(); // 返回 "440123****1234"
        /// </code>
        /// </example>
        /// <remarks>
        /// 保留前6位（地区代码和部分出生日期）和后4位，中间部分用*代替。
        /// 适用于中国驾驶证号码格式（18位）。
        /// 10位以下的输入不进行脱敏，避免误处理其他类型证件。
        /// 性能优化：使用AsSpan减少字符串分配。
        /// </remarks>
        public static string? MaskDriverLicense(this string? driverLicense)
        {
            if (string.IsNullOrEmpty(driverLicense) || driverLicense.Length < 10)
                return driverLicense;

            return string.Concat(
                driverLicense.AsSpan(0, 6),
                "****",
                driverLicense.AsSpan(driverLicense.Length - 4)
            );
        }

        /// <summary>
        /// 对序列号进行脱敏，保护产品序列号信息。
        /// </summary>
        /// <param name="serialNumber">要脱敏的序列号。</param>
        /// <returns>脱敏后的序列号，如果输入为null或长度不足则返回原值。</returns>
        /// <example>
        /// <code>
        /// string sn1 = "SN123456789ABC";
        /// string masked1 = sn1.MaskSerialNumber(); // 返回 "SN12****9ABC"
        /// 
        /// string sn2 = "DELL-ABC123-XYZ789";
        /// string masked2 = sn2.MaskSerialNumber(); // 返回 "DELL****Z789"
        /// </code>
        /// </example>
        /// <remarks>
        /// 保留前4位和后4位，中间部分用*代替。
        /// 8位以下的序列号不进行脱敏。
        /// 性能优化：使用AsSpan减少字符串分配。
        /// </remarks>
        public static string? MaskSerialNumber(this string? serialNumber)
        {
            if (string.IsNullOrEmpty(serialNumber) || serialNumber.Length <= 8)
                return serialNumber;

            return string.Concat(
                serialNumber.AsSpan(0, 4),
                "****",
                serialNumber.AsSpan(serialNumber.Length - 4)
            );
        }

        /// <summary>
        /// 对JWT Token进行脱敏，保护认证令牌信息。
        /// </summary>
        /// <param name="jwtToken">要脱敏的JWT Token。</param>
        /// <returns>脱敏后的Token，如果输入为null或格式无效则返回处理后的结果。</returns>
        /// <example>
        /// <code>
        /// string token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c";
        /// string masked = token.MaskJwtToken(); 
        /// // 返回 "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.******.******"
        /// 
        /// // 用于API日志记录
        /// logger.Info($"请求Token: {request.AuthToken.MaskJwtToken()}");
        /// </code>
        /// </example>
        /// <remarks>
        /// 保留JWT的Header部分（第一段），便于识别token类型和算法。
        /// 隐藏Payload（载荷）和Signature（签名）部分，保护敏感信息。
        /// 对于格式错误的token，返回统一的脱敏格式。
        /// 性能优化：使用IndexOf代替Split，减少数组分配。
        /// </remarks>
        public static string? MaskJwtToken(this string? jwtToken)
        {
            if (string.IsNullOrEmpty(jwtToken)) return jwtToken;

            int firstDot = jwtToken.IndexOf('.');
            if (firstDot == -1) return "******.******.******";

            int secondDot = jwtToken.IndexOf('.', firstDot + 1);
            if (secondDot == -1) return "******.******.******";

            return string.Concat(jwtToken.AsSpan(0, firstDot), ".******.******");
        }

        #endregion

        #region 便捷扩展方法

        /// <summary>
        /// 检查字符串是否需要脱敏（包含敏感信息特征）。
        /// </summary>
        /// <param name="value">要检查的字符串。</param>
        /// <returns>如果可能包含敏感信息则返回true。</returns>
        /// <example>
        /// <code>
        /// string text1 = "13812345678";
        /// bool needsMask = text1.NeedsMasking(); // 可能返回 true（类似手机号）
        /// 
        /// string text2 = "hello world";
        /// bool needsMask2 = text2.NeedsMasking(); // 可能返回 false
        /// 
        /// // 批量处理时的预检查
        /// if (userInput.NeedsMasking())
        /// {
        ///     processedData = userInput.MaskText();
        /// }
        /// </code>
        /// </example>
        /// <remarks>
        /// 简单的启发式检查，包括：
        /// - 连续数字（可能是手机号、身份证等）
        /// - 邮箱格式
        /// - 包含@符号的字符串
        /// 此方法用于快速筛选，具体脱敏仍需使用对应的脱敏方法。
        /// 性能优化：使用早期返回和高效的字符检查。
        /// </remarks>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool NeedsMasking(this string? value)
        {
            if (string.IsNullOrEmpty(value)) return false;

            // 快速检查邮箱格式
            if (value.Contains('@')) return true;

            // 快速检查数字密度
            if (value.Length >= 8)
            {
                int digitCount = 0;
                for (int i = 0; i < value.Length; i++)
                {
                    if (char.IsDigit(value[i]))
                    {
                        digitCount++;
                        if (digitCount >= 8 && value.Length <= 20) return true; // 可能是手机号或身份证
                        if (digitCount >= 12 && value.Length >= 15) return true; // 可能是银行卡
                    }
                }
            }

            return false;
        }

        /// <summary>
        /// 智能脱敏：自动识别字符串类型并应用相应的脱敏规则。
        /// </summary>
        /// <param name="value">要脱敏的字符串。</param>
        /// <returns>脱敏后的字符串。</returns>
        /// <example>
        /// <code>
        /// string email = "john@example.com";
        /// string masked1 = email.SmartMask(); // 自动识别为邮箱并脱敏
        /// 
        /// string phone = "13812345678";
        /// string masked2 = phone.SmartMask(); // 自动识别为手机号并脱敏
        /// 
        /// // 批量智能脱敏
        /// var maskedData = userData.Select(x => x.SmartMask()).ToList();
        /// </code>
        /// </example>
        /// <remarks>
        /// 使用简单的模式匹配来识别常见的敏感信息类型：
        /// - 包含@符号：按邮箱脱敏
        /// - 11位纯数字：按手机号脱敏
        /// - 15或18位数字：按身份证脱敏
        /// - 16-19位数字：按银行卡脱敏
        /// - 其他：按通用文本脱敏
        /// 准确性有限，建议在已知数据类型时使用专用脱敏方法。
        /// 性能优化：使用早期返回和高效的模式检查。
        /// </remarks>
        public static string? SmartMask(this string? value)
        {
            if (string.IsNullOrEmpty(value)) return value;

            // 邮箱检查
            if (value.Contains('@'))
            {
                int atCount = 0;
                for (int i = 0; i < value.Length; i++)
                {
                    if (value[i] == '@')
                    {
                        atCount++;
                        if (atCount > 1) break;
                    }
                }
                if (atCount == 1) return value.MaskEmail();
            }

            // 纯数字检查
            bool allDigits = true;
            for (int i = 0; i < value.Length; i++)
            {
                if (!char.IsDigit(value[i]))
                {
                    allDigits = false;
                    break;
                }
            }

            if (allDigits)
            {
                return value.Length switch
                {
                    11 when value[0] == '1' => value.MaskPhone(),
                    15 or 18 => value.MaskIdCard(),
                    >= 16 and <= 19 => value.MaskBankCard(),
                    _ => value.MaskText()
                };
            }

            // 默认通用脱敏
            return value.MaskText();
        }

        #endregion
    }
}
